package com.caocaog.market.common;

import com.alibaba.fastjson.JSONObject;
import com.caocaog.market.entity.PushMessageTemplate;
import com.getui.push.v2.sdk.ApiHelper;
import com.getui.push.v2.sdk.GtApiConfiguration;
import com.getui.push.v2.sdk.api.PushApi;
import com.getui.push.v2.sdk.api.StatisticApi;
import com.getui.push.v2.sdk.api.UserApi;
import com.getui.push.v2.sdk.common.ApiResult;
import com.getui.push.v2.sdk.dto.CommonEnum;
import com.getui.push.v2.sdk.dto.req.Audience;
import com.getui.push.v2.sdk.dto.req.AudienceDTO;
import com.getui.push.v2.sdk.dto.req.Settings;
import com.getui.push.v2.sdk.dto.req.message.PushChannel;
import com.getui.push.v2.sdk.dto.req.message.PushDTO;
import com.getui.push.v2.sdk.dto.req.message.PushMessage;
import com.getui.push.v2.sdk.dto.req.message.android.AndroidDTO;
import com.getui.push.v2.sdk.dto.req.message.android.ThirdNotification;
import com.getui.push.v2.sdk.dto.req.message.android.Ups;
import com.getui.push.v2.sdk.dto.req.message.ios.Alert;
import com.getui.push.v2.sdk.dto.req.message.ios.Aps;
import com.getui.push.v2.sdk.dto.req.message.ios.IosDTO;
import com.getui.push.v2.sdk.dto.req.message.ios.Multimedia;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @see <a href="https://uniapp.dcloud.io/unipush.html">uniPush文档</a>
 */
@Slf4j
@Component
public class PushUtils {

    private static String appId/* = "Hnjg1CIwAL842kWMhjCdN"*/;
    private static String appKey/* = "z6EPQPnHKb8N4eXipBua36"*/;
    private static String masterSecret/* = "VmIVI91Iag54NZtb5E6M5A"*/;
    private static Integer ttl/* = 3600000*/;

    private static String packageName/* = "com.ccpt.biz"*/;
    private static String aliasPrefix/* = "market_merchant_"*/;



    public static PushApi pushApi;
    public static UserApi userApi;
    public static StatisticApi statisticApi;
    private static ApiHelper apiHelper;
    private static final String BADGE_ADD_NUM = "1";
    private static final String XM_CHANNEL_ID = "high_system";
    private static final String OP_CHANNEL_ID = "newOrder";


    public static void main(String[] args) {
        initApi();
        PushMessageTemplate pushMessageTemplate = new PushMessageTemplate().setId(1).setTitle("曹操跑腿啦啦啦").setContent("噗噗噗不不不");
        PushDTO<Audience> pushDTO = PushUtils.buildPushDTO(pushMessageTemplate, "rider_1531174542653444098");
        System.out.println(pushDTO);
        ApiResult<Map<String, Map<String, String>>> apiResult = pushApi.pushToSingleByAlias(pushDTO);

        System.out.println(apiResult.getData());
    }


    /**
     * 初始化
     */
    public static void initApi() {
        if (apiHelper == null) {
            apiHelper = createApiHelper();
        }
        pushApi = apiHelper.creatApi(PushApi.class);
        userApi = apiHelper.creatApi(UserApi.class);
        statisticApi = apiHelper.creatApi(StatisticApi.class);
    }

    private static boolean verificationParameter() {
        return appId != null && appKey != null && masterSecret != null;
    }

    /**
     * 创建 ApiHelper 可用于创建PushApi、StatisticApi、UserApi
     */
    private static ApiHelper createApiHelper() {
        GtApiConfiguration apiConfiguration = new GtApiConfiguration();
        apiConfiguration.setAppId(appId);
        apiConfiguration.setAppKey(appKey);
        apiConfiguration.setMasterSecret(masterSecret);
        // 实例化ApiHelper对象，用于创建接口对象
        return ApiHelper.build(apiConfiguration);
    }

    /**
     * 重新创建 ApiHelper，一般用于重新{@link #initApi 初始化}
     */
    public static void recreateApiHelper() {
        apiHelper = createApiHelper();
    }

    /**
     * 构建推送体DTO
     *
     * @param pushMessageTemplate 推送消息模版(title, content, payload)
     * @param alias                别名
     */
    public static PushDTO<Audience> buildPushDTO(PushMessageTemplate pushMessageTemplate, String alias) {
        PushDTO<Audience> pushDTO = new PushDTO<>();
        // 设置推送参数，requestId 需要每次变化唯一
        pushDTO.setRequestId(Long.toString(System.currentTimeMillis()));
        pushDTO.setSettings(buildSettings());
        pushDTO.setPushMessage(buildPushMessage(pushMessageTemplate));
        pushDTO.setPushChannel(buildPushChannel(pushMessageTemplate));
        if (alias != null) {
            pushDTO.setAudience(buildAudience(alias));
        }

        return pushDTO;
    }

    /**
     * 构建群推接受人
     *
     * @param taskId 任务id
     * @param alias  别名集合
     */
    public static AudienceDTO buildAudienceDTO(String taskId, String... alias) {
        AudienceDTO audienceDTO = new AudienceDTO();
        audienceDTO.setTaskid(taskId);
        audienceDTO.setAudience(buildAudience(alias));
        return audienceDTO;
    }

    /**
     * 构建单推单接收人
     *
     * @param alias 别名集合
     */
    public static Audience buildAudience(String... alias) {
        Audience audience = new Audience();
        /*
         * 别名相关限制
         * 别名名称：长度40字节，支持中、英文（区分大小写）、数字以及下划线
         * 一个CID一天绑定别名和解绑别名次数各有50次机会
         * 一个别名下最多绑定10个CID，若超出10个，则绑定后者，剔除第一个已绑定的CID，以此类推；一个CID只能绑定一个别名，若超出则以最后一次绑定的别名为准。
         * */
        audience.setAlias(handlerAlias(alias));

        return audience;
    }

    /**
     * 构建推送设置
     */
    public static Settings buildSettings() {
        Settings settings = new Settings();
        // 消息有效期，走厂商消息必须设置该值
        settings.setTtl(ttl);
        return settings;
    }

    /**
     * 构建 PushMessage
     *
     * @param pushMessageTemplate 推送消息模版(title, content, payload)
     */
    public static PushMessage buildPushMessage(PushMessageTemplate pushMessageTemplate) {
        PushMessage pushMessage = new PushMessage();
        pushMessage.setNetworkType(CommonEnum.NetworkTypeEnum.TYPE_ALL.get());
        pushMessage.setTransmission(buildPayload(pushMessageTemplate));
        log.info(pushMessage.getTransmission());

        return pushMessage;
    }

    private static String buildPayload(PushMessageTemplate pushMessageTemplate) {

        if (pushMessageTemplate.getPayload() == null)
            pushMessageTemplate.setPayload(new LinkedHashMap<>());

        Map<String, Object> collect = Stream.of(pushMessageTemplate.getPayload(), ImmutableMap.of(
                        "type", pushMessageTemplate.getId(),
                        "title", pushMessageTemplate.getTitle(),
                        "content", pushMessageTemplate.getContent()
                ))
                .flatMap(map -> map.entrySet().stream())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (entryA, entryB) -> entryA));
        return new JSONObject(collect).toJSONString();
    }

    /**
     * 构建 PushChannel
     *
     * @see <a href="https://docs.getui.com/getui/server/rest_v2/common_args/?id=android-">厂商通道参数文档 Android</a>
     * @see <a href="https://docs.getui.com/getui/server/rest_v2/common_args/?id=ios-">厂商通道参数文档 iOS</a>
     */
    public static PushChannel buildPushChannel(PushMessageTemplate pushMessageTemplate) {
        PushChannel pushChannel = new PushChannel();

        /*
          安卓离线厂商通道推送的消息体
         */
        AndroidDTO androidDTO = new AndroidDTO();
        Ups ups = new Ups();
        ThirdNotification thirdNotification = new ThirdNotification();
        thirdNotification.setTitle(pushMessageTemplate.getTitle());
        thirdNotification.setBody(pushMessageTemplate.getContent());
        thirdNotification.setClickType("intent");
        thirdNotification.setIntent("intent://io.dcloud.unipush/?#Intent;scheme=unipush;launchFlags=0x4000000;action=android.intent.action.oppopush;component=" + packageName + "/io.dcloud.PandoraEntry;S.gttask=;S.UP-OL-SU=true;S.title=" + pushMessageTemplate.getTitle() + ";S.content=" + pushMessageTemplate.getContent() + ";S.payload=" + buildPayload(pushMessageTemplate) + ";end");

        ups.setNotification(thirdNotification);

        /*
         * 注意：自定义铃声受华为自己通知消息权重影响
         * 自定义通知渠道仅对发送给用户设备的服务与通讯级别消息有效，
         * 一般级别消息仍然通过华为营销通知渠道展示（一般级别消息是不会播放自定义铃声）。
         * 这个时候就不会播放自定义铃声了。消息类别受华为侧AI智能判断控制，或开发者自己向华为侧申请自分类权益申请.
         * https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides-V5/message-frequency-restriction-0000001149358835-V5#ZH-CN_TOPIC_0000001149358835__section893184112272
         * */
        ups.addOption(Options.HW, "/message/android/notification/badge/class", "io.dcloud.PandoraEntry");
        ups.addOption(Options.HW, "/message/android/notification/importance", "HIGH");

        /*
         * 小米推送的消息通道分为“普通消息”（默认）和“重要消息”两类，默认下发普通消息。普通消息单日可推送数量有限制，重要消息不限。
         * high_system 是申请到的
         * */
        ups.addOption(Options.XM, "/extra.channel_id", XM_CHANNEL_ID);

        /*
         * oppo同上
         * 注意事项
         * 1.该接口需要联系个推技术人员申请开通才可以使用
         * 2.OPPO私信消息仅支持单推
         * 3.如果使用私信，需要在客户端创建对应的私信渠道，具体请参考: <a href="https://open.oppomobile.com/wiki/doc#id=10289">通知通道（Channel）适配</a>
         * */
        ups.addOption(Options.OP, "/channel_id", OP_CHANNEL_ID);

        androidDTO.setUps(ups);
        pushChannel.setAndroid(androidDTO);

        /*
          ios离线apn通道推送的消息体
         */
        IosDTO iosDTO = new IosDTO();
        /* voip：voip语音推送，notify：apns通知消息 */
        iosDTO.setType("notify");
        iosDTO.setAutoBadge("+" + BADGE_ADD_NUM);
        iosDTO.setPayload(buildPayload(pushMessageTemplate));
        Aps aps = new Aps();
        aps.setThreadId(packageName);
        Alert alert = new Alert();
        alert.setTitle(pushMessageTemplate.getTitle());
        alert.setBody(pushMessageTemplate.getContent());
        aps.setAlert(alert);
        iosDTO.setAps(aps);
        Multimedia multimedia = new Multimedia();
        multimedia.setType(1);
        multimedia.setUrl("https://img.mxomo.com/cover/vol/0083/51267/1004.jpg!350x500?sign=1622360186-60186-0-877f1b7fb09bf02964ace4f958f4c876");
        multimedia.setOnlyWifi(Boolean.FALSE);
        iosDTO.setMultimedia(Collections.singletonList(multimedia));
        pushChannel.setIos(iosDTO);

        return pushChannel;
    }

    /**
     * 处理别名，添加前缀
     *
     * @param alias 别名
     */
    private static List<String> handlerAlias(String... alias) {
        return Arrays.stream(alias)
                .filter(item -> item != null && !item.contains(aliasPrefix))
                .map(item -> aliasPrefix + item)
                .collect(Collectors.toList());
    }

    @Value("${uni-push.app-id}")
    private void setAppId(String aId) {
        appId = aId;
        if (verificationParameter()) initApi();
    }

    @Value("${uni-push.app-key}")
    private void setAppKey(String aKey) {
        appKey = aKey;
        if (verificationParameter()) initApi();
    }

    @Value("${uni-push.master-secret}")
    private void setMasterSecret(String ms) {
        masterSecret = ms;
        if (verificationParameter()) initApi();
    }

    @Value("${uni-push.ttl}")
    private void setTtl(Integer t) {
        ttl = t;
    }

    @Value("${uni-push.package-name}")
    private void setTtl(String pn) {
        packageName = pn;
    }

    @Value("${uni-push.alias-prefix}")
    private void setAliasPrefix(String ap) {
        aliasPrefix = ap;
    }

}
